/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved.
 */

package com.baidu.process.cloud.apigateway.sdk.utils;

import com.baidu.process.cloud.apigateway.sdk.utils.AccessServiceOkhttp;
import com.baidu.process.cloud.apigateway.sdk.utils.Request;
import com.baidu.process.cloud.apigateway.sdk.utils.UnknownHttpMethodException;
import com.baidu.process.cloud.sdk.auth.signer.Signer;
import com.baidu.process.cloud.sdk.http.HttpMethodName;

import okhttp3.MediaType;
import okhttp3.RequestBody;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;

public class AccessServiceOkhttpImpl extends AccessServiceOkhttp {
    private static final String UTF8 = "UTF-8";
    private static final String OPTIONS = "OPTIONS";

    public AccessServiceOkhttpImpl(String ak, String sk) {
        super(ak, sk);
    }

    public AccessServiceOkhttpImpl(String ak, String sk, String messageDigestAlgorithm) {
        super(ak, sk, messageDigestAlgorithm);
    }

    @Override
    public okhttp3.Request access(String url, Map<String, String> headers, String entity, HttpMethodName httpMethod)
            throws Exception {
        com.baidu.process.cloud.apigateway.sdk.utils.Request request = new Request();
        request.setAppKey(ak);
        request.setAppSecrect(sk);
        request.setMethod(httpMethod.name());
        request.setUrl(url);
        for (Map.Entry<String, String> map : headers.entrySet()) {
            request.addHeader(map.getKey(), map.getValue());
        }
        request.setBody(entity);

        Signer signer = new Signer(messageDigestAlgorithm);
        // Sign the request, and the request will change after the signing.
        signer.sign(request);
        return createRequest(url, request.getHeaders(), entity, httpMethod);
    }

    public okhttp3.Request access(String url, Map<String, String> headers, InputStream content, Long contentLength,
            HttpMethodName httpMethod) throws Exception {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = content.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }
        String body = result.toString(UTF8);
        return access(url, headers, body, httpMethod);
    }

    private static okhttp3.Request createRequest(String url, Map<String, String> headers, String body,
            HttpMethodName httpMethod) throws Exception {
        if (body == null) {
            body = "";
        }
        RequestBody entity = RequestBody.create(MediaType.parse(""), body.getBytes(UTF8));
        okhttp3.Request httpRequest;
        if (httpMethod == HttpMethodName.POST) {
            httpRequest = new okhttp3.Request.Builder().url(url).post(entity).build();
        } else if (httpMethod == HttpMethodName.PUT) {
            httpRequest = new okhttp3.Request.Builder().url(url).put(entity).build();
        } else if (httpMethod == HttpMethodName.PATCH) {
            httpRequest = new okhttp3.Request.Builder().url(url).patch(entity).build();
        } else if (httpMethod == HttpMethodName.DELETE) {
            httpRequest = new okhttp3.Request.Builder().url(url).delete(entity).build();
        } else if (httpMethod == HttpMethodName.GET) {
            httpRequest = new okhttp3.Request.Builder().url(url).get().build();
        } else if (httpMethod == HttpMethodName.HEAD) {
            httpRequest = new okhttp3.Request.Builder().url(url).head().build();
        } else if (httpMethod == HttpMethodName.OPTIONS) {
            httpRequest = new okhttp3.Request.Builder().url(url).method(OPTIONS, null).build();
        } else {
            throw new UnknownHttpMethodException("Unknown HTTP method name: " + httpMethod);
        }
        for (Map.Entry<String, String> map : headers.entrySet()) {
            httpRequest = httpRequest.newBuilder().addHeader(map.getKey(), map.getValue()).build();
        }
        return httpRequest;
    }
}
